import os
import datetime
import chardet
import re
from typing import List, Dict, Optional


def read_prompt_file(file_path: str) -> str:
    """
    读取提示词文件
    
    Args:
        file_path: 文件路径
        
    Returns:
        文件内容
        
    Raises:
        Exception: 如果文件读取失败
    """
    try:
        # 首先读取文件的二进制数据
        with open(file_path, 'rb') as f:
            raw_data = f.read()
        
        # 使用chardet检测文件编码
        result = chardet.detect(raw_data)
        encoding = result['encoding']
        confidence = result.get('confidence', 0)
        
        print(f"检测到文件编码: {encoding}, 置信度: {confidence}")
        
        # 如果检测到的编码可靠性较低或者为None，则使用一系列常见编码尝试
        if not encoding or confidence < 0.7:
            encodings_to_try = ['utf-8', 'utf-8-sig', 'gbk', 'gb2312', 'gb18030', 'big5', 'latin-1']
        else:
            encodings_to_try = [encoding] + ['utf-8', 'utf-8-sig', 'gbk', 'gb2312', 'gb18030', 'big5', 'latin-1']
        
        # 记录尝试的编码情况
        decode_results = {}
        
        # 尝试不同的编码
        for enc in encodings_to_try:
            try:
                content = raw_data.decode(enc)
                decode_results[enc] = "成功"
                # 检查解码后的内容是否包含乱码特征
                if '[?]' in content or '\ufffd' in content:
                    print(f"使用{enc}解码可能存在乱码")
                    continue
                
                print(f"成功使用{enc}编码解码文件")
                # 添加预处理步骤
                processed_content = preprocess_prompt_content(content)
                return processed_content
            except UnicodeDecodeError as e:
                decode_results[enc] = f"失败: {str(e)}"
                continue
        
        # 打印所有尝试的编码结果，用于调试
        print("文件编码尝试结果:")
        for enc, result in decode_results.items():
            print(f"  {enc}: {result}")
        
        # 如果所有编码都失败，最后尝试使用errors='replace'选项
        fallback_encoding = encodings_to_try[0]
        content = raw_data.decode(fallback_encoding, errors='replace')
        print(f"使用{fallback_encoding}编码(替换模式)解码文件")
        # 添加预处理步骤
        processed_content = preprocess_prompt_content(content)
        return processed_content
    except Exception as e:
        raise Exception(f"读取提示词文件错误: {str(e)}")


def preprocess_prompt_content(content: str) -> str:
    """
    预处理提示词内容，确保特殊格式和字符被正确处理，同时尽量保留原始格式
    
    Args:
        content: 原始提示词内容
        
    Returns:
        处理后的提示词内容
    """
    # 保存原始内容用于比较
    original_content = content
    
    # 检测是否含有Markdown或类似表格、代码块等需要保留格式的内容
    has_markdown = any(marker in content for marker in ['```', '|', '#', '- ', '1. ', '```Thinking'])
    has_special_format = any(marker in content for marker in ['[[', ']]', '<>', '**', '"""'])
    
    # 如果检测到特殊格式，则减少格式替换操作
    if has_markdown or has_special_format:
        # 仅进行最小的必要替换，避免破坏格式
        # 步骤1: 仅在确认需要的情况下替换角色标记
        if '[角色]' in content and '【角色】' not in content:
            content = re.sub(r'\[角色\](?=\s|$)', '【角色】', content)
        
        # 仅处理明确的表格问题
        if re.search(r'\|\s*\|', content):
            # 修复表格中连续的分隔符，但不影响其他使用|的地方
            content = re.sub(r'(\|)\s*(\|)', r'\1  \2', content)
        
        # 打印处理情况
        if content != original_content:
            print(f"检测到特殊格式内容，执行最小替换")
            print(f"处理前内容长度: {len(original_content)}, 处理后内容长度: {len(content)}")
        
        return content
    
    # 对于普通内容，可以进行更全面的优化
    # 步骤1: 处理特殊的角色标记格式 
    content = re.sub(r'\[角色\]\s*', '【角色】', content)
    
    # 步骤2: 处理特殊的表格和分隔符
    # 标准化表格分隔符 
    content = re.sub(r'\|\s*\|', '|  |', content)
    
    # 步骤3: 谨慎处理特殊符号，仅在必要时替换
    # 仅替换孤立的，确定会引起问题的符号
    replacements = {}
    
    # 检查内容中是否有确实需要替换的特殊符号
    # 例如，仅当**被用作强调而不是代码时才替换
    if re.search(r'([^`]|^)\*\*([^`]|$)', content):
        replacements['**'] = '✱✱'  # 替换双星号为Unicode字符
    
    # 仅当<>被用作标签或箭头而不是代码时才替换
    if re.search(r'([^`]|^)<>([^`]|$)', content):
        replacements['<>'] = '⟨⟩'  # 替换尖括号为Unicode字符
    
    # 仅当[]被用作标记而不是代码或数组索引时才替换
    if re.search(r'([^`]|^)\[\]([^`]|$)', content):
        replacements['[]'] = '【】'  # 替换方括号为全角字符
    
    # 应用已确认需要的替换
    for old, new in replacements.items():
        content = content.replace(old, new)
    
    # 步骤4: 谨慎处理多行引号，仅在确定需要时才替换
    if '"""' in content and not ('```' in content):
        content = content.replace('"""', '「」')
    
    # 打印处理情况
    if content != original_content:
        print(f"提示词预处理: 内容已优化，保留特殊格式")
        print(f"处理前内容长度: {len(original_content)}, 处理后内容长度: {len(content)}")
    
    return content


def generate_follow_up_prompt(round_num: int, previous_response: str, custom_prompts: Optional[List[str]] = None) -> str:
    """
    生成后续对话的提示词
    
    Args:
        round_num: 对话轮次编号
        previous_response: 前一轮对话的响应
        custom_prompts: 自定义的多轮对话提示词列表
        
    Returns:
        生成的后续提示词
    """
    # 如果提供了自定义提示词列表且长度足够，使用自定义提示词
    if custom_prompts and round_num < len(custom_prompts):
        return custom_prompts[round_num]
    
    # 否则使用默认提示词
    default_prompts = [
        "基于你上面的回答，请更详细地展开第一个要点。",
        "请提供一些具体的例子或案例来说明你在上一轮回答中的观点。",
        "请总结一下我们整个对话的要点，并提出进一步的行动建议。"
    ]
    
    if round_num < len(default_prompts):
        return default_prompts[round_num]
    else:
        return f"请针对上一轮回答进行进一步的提问或深入探讨。"


def generate_note(conversations: List[Dict[str, str]], original_prompt_file: str) -> str:
    """
    从对话生成笔记内容
    
    Args:
        conversations: 对话列表，每个对话是一个包含prompt和response的字典
        original_prompt_file: 原始提示词文件路径
        
    Returns:
        生成的笔记内容
    """
    now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    note_content = f"# Claude 对话笔记 - {now}\n\n"
    
    # 添加原始提示词信息
    note_content += f"## 原始提示词文件\n\n`{original_prompt_file}`\n\n"
    
    # 添加每轮对话内容
    for i, conv in enumerate(conversations):
        note_content += f"## 对话 {i+1}\n\n"
        note_content += f"### 提示词\n\n```\n{conv['prompt']}\n```\n\n"
        note_content += f"### Claude 回复\n\n{conv['response']}\n\n"
        note_content += "---\n\n"
    
    # 添加总结部分
    note_content += f"## 笔记信息\n\n"
    note_content += f"- 生成时间: {now}\n"
    note_content += f"- 对话轮数: {len(conversations)}\n"
    
    return note_content


def save_note(note_content: str, save_path: str) -> bool:
    """
    保存笔记到文件
    
    Args:
        note_content: 笔记内容
        save_path: 保存路径
        
    Returns:
        是否保存成功
    """
    try:
        # 确保目录存在
        os.makedirs(os.path.dirname(save_path), exist_ok=True)
        
        # 写入文件
        with open(save_path, 'w', encoding='utf-8') as f:
            f.write(note_content)
        
        return True
    except Exception as e:
        print(f"保存笔记文件错误: {str(e)}")
        return False


def get_default_save_path() -> str:
    """
    获取默认的笔记保存路径
    
    Returns:
        默认保存路径
    """
    now = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
    documents_dir = os.path.expanduser("~/Documents")
    
    # 创建Claude笔记目录
    claude_notes_dir = os.path.join(documents_dir, "Claude_Notes")
    os.makedirs(claude_notes_dir, exist_ok=True)
    
    return os.path.join(claude_notes_dir, f"Claude_Note_{now}.md") 